import { EventEmitter } from "events";
import chokidar, { FSWatcher } from "chokidar";
import path from "path";

import { IEmbedder, IVectorStore, ICodeParser, IndexStatus, IndexingStats, FileWatcherEvent, PointStruct } from "../interfaces/index.js";
import { DirectoryScanner } from "./directory-scanner.js";
import { CacheManager } from "./cache-manager.js";
import { validatePath } from "../utils/path-utils.js";
import { CODE_FILE_EXTENSIONS as CODE_EXTENSIONS } from "../constants/index.js";
import { InstructionManager, DocumentType } from "../utils/instruction-manager.js";

export class CodeIndexOrchestrator extends EventEmitter {
  private directoryScanner: DirectoryScanner;
  private fileWatcher?: FSWatcher;
  private currentStatus: IndexStatus = {
    state: 'standby',
    message: 'Ready to index',
  };

  constructor(
    private readonly embedder: IEmbedder,
    private readonly vectorStore: IVectorStore,
    private readonly codeParser: ICodeParser,
    private readonly cacheManager: CacheManager,
    private readonly configDirectory: string = process.cwd(),
  ) {
    super();
    this.directoryScanner = new DirectoryScanner(
      embedder,
      vectorStore,
      codeParser,
      cacheManager
    );
  }

  private getDocumentType(filePath: string): DocumentType {
    const ext = path.extname(filePath).toLowerCase();
    return CODE_EXTENSIONS.includes(ext) ? "code" : "text";
  }

  getStatus(): IndexStatus {
    return { ...this.currentStatus };
  }

  async startIndexing(directoryPath: string, verbose: boolean = false): Promise<void> {
    const pathValidation = await validatePath(directoryPath);
    if (!pathValidation.valid) throw new Error(pathValidation.error);

    this.updateStatus('indexing', 'Initializing...');
    if (await this.vectorStore.initialize()) {
      await this.cacheManager.clearCache();
    }
    await this.cacheManager.loadCache();

    this.updateStatus('indexing', 'Scanning directory...');
    const stats = await this.directoryScanner.scanDirectory(
      directoryPath,
      (progress) => this.updateStatus('indexing', `Processing files...`, progress),
      (error) => this.emit('error', error),
      verbose,
      this.configDirectory
    );

    if (stats.errors === 0 || stats.processed > 0) {
      this.updateStatus('indexed', `Indexing complete.`, stats);
    } else {
      this.updateStatus('error', `Indexing failed.`, stats);
    }
    this.emit('indexingComplete', stats);
  }

  async searchIndexWithCategories(
    query: string,
    directoryPrefix?: string,
    maxResults?: number,
    minScore?: number,
    textMinScore?: number,
    codeMinScore?: number,
  ): Promise<{ textResults: any[]; codeResults: any[]; combinedResults: any[] }> {
    
    const codeQuery = InstructionManager.getInstruction("retrieval_query", "code", query);
    const textQuery = InstructionManager.getInstruction("retrieval_query", "text", query);

    const [{ embeddings: codeEmbeddings }, { embeddings: textEmbeddings }] = await Promise.all([
        this.embedder.createEmbeddings([codeQuery], "code", "retrieval_query"),
        this.embedder.createEmbeddings([textQuery], "text", "retrieval_query"),
    ]);

    const [codeResults, textResults] = await Promise.all([
        this.vectorStore.search(codeEmbeddings[0], "code", directoryPrefix, codeMinScore, maxResults),
        this.vectorStore.search(textEmbeddings[0], "text", directoryPrefix, textMinScore, maxResults),
    ]);

    const combinedResults = [...textResults, ...codeResults].sort((a, b) => b.score - a.score);
    return { textResults, codeResults, combinedResults };
  }

  async clearIndex(): Promise<void> {
    this.updateStatus('indexing', 'Clearing index...');
    await this.vectorStore.deleteCollection();
    await this.cacheManager.clearCache();
    this.updateStatus('standby', 'Index cleared');
    this.emit('indexCleared');
  }

  private updateStatus(state: IndexStatus['state'], message: string, stats?: IndexingStats): void {
    this.currentStatus = { state, message, stats };
    this.emit('statusChanged', this.currentStatus);
  }
}
